from django.core import serializers
from rest_framework.decorators import action
from rest_framework.utils import json

from dvadmin.system.models import Orders, OrderGoods, Users, Goods
from dvadmin.utils.json_response import DetailResponse, SuccessResponse, ErrorResponse
from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.viewset import CustomModelViewSet


class OrdersSerializer(CustomModelSerializer):
    """
    订单管理接口-序列化器
    """

    class Meta:
        model = Orders
        fields = "__all__"
        read_only_fields = ["id"]


class OrdersCreateUpdateSerializer(CustomModelSerializer):
    """
    订单管理接口 创建/更新时的序列化器
    """

    def validate(self, attrs: dict):
        return super().validate(attrs)

    class Meta:
        model = Orders
        fields = '__all__'


class OrdersViewSet(CustomModelViewSet):
    """
    订单管理接口
    """
    queryset = Orders.objects.all()
    serializer_class = OrdersSerializer
    create_serializer_class = OrdersCreateUpdateSerializer

    def get_paypal_access_token(self):
        """获取PayPal访问令牌"""
        try:
            # PayPal API凭证
            CLIENT_ID = settings.PAYPAL_CLIENT_ID
            CLIENT_SECRET = settings.PAYPAL_CLIENT_SECRET
            
            url = "https://api-m.sandbox.paypal.com/v1/oauth2/token"
            headers = {
                "Accept": "application/json",
                "Accept-Language": "en_US"
            }
            auth = (CLIENT_ID, CLIENT_SECRET)
            data = {"grant_type": "client_credentials"}
            
            response = requests.post(url, headers=headers, auth=auth, data=data)
            response.raise_for_status()
            return response.json()["access_token"]
        except Exception as e:
            return None

    @action(methods=['POST'], detail=False)
    def create_order(self, request):
        """
        创建PayPal订单
        """
        try:
            access_token = self.get_paypal_access_token()
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            # 从请求中获取订单信息
            amount = request.data.get('amount', '10.00')
            currency = request.data.get('currency', 'USD')
            
            payload = {
                "intent": "CAPTURE",
                "purchase_units": [{
                    "amount": {
                        "currency_code": currency,
                        "value": amount
                    }
                }],
                "application_context": {
                    "return_url": f"{settings.FRONTEND_URL}/payment/success",
                    "cancel_url": f"{settings.FRONTEND_URL}/payment/cancel"
                }
            }

            response = requests.post(
                'https://api-m.sandbox.paypal.com/v2/checkout/orders',
                headers=headers,
                json=payload
            )
            
            if response.status_code == 201:
                order_data = response.json()
                # 保存订单信息到数据库
                order = Orders.objects.create(
                    order_id=order_data['id'],
                    amount=amount,
                    currency=currency,
                    status='CREATED',
                    user=request.user
                )
                return DetailResponse(data={
                    'order_id': order_data['id'],
                    'links': order_data['links']
                })
            else:
                return ErrorResponse(msg="Failed to create PayPal order")

        except Exception as e:
            return ErrorResponse(msg=f"Error creating order: {str(e)}")

    @action(methods=['POST'], detail=True)
    def capture_payment(self, request, pk=None):
        """
        捕获支付
        """
        try:
            order = self.get_object()
            access_token = self.get_paypal_access_token()
            
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            response = requests.post(
                f'https://api-m.sandbox.paypal.com/v2/checkout/orders/{order.order_id}/capture',
                headers=headers
            )

            if response.status_code in [200, 201]:
                capture_data = response.json()
                # 更新订单状态
                order.status = capture_data['status']
                order.payment_id = capture_data['purchase_units'][0]['payments']['captures'][0]['id']
                order.save()
                
                return DetailResponse(data={
                    'order_id': order.order_id,
                    'status': order.status,
                    'payment_id': order.payment_id
                })
            else:
                return ErrorResponse(msg="Payment capture failed")

        except Exception as e:
            return ErrorResponse(msg=f"Error capturing payment: {str(e)}")

    @action(methods=['POST'], detail=True)
    def refund_payment(self, request, pk=None):
        """
        退款处理
        """
        try:
            order = self.get_object()
            if not order.payment_id:
                return ErrorResponse(msg="No payment ID found for this order")

            access_token = self.get_paypal_access_token()
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            response = requests.post(
                f'https://api-m.sandbox.paypal.com/v2/payments/captures/{order.payment_id}/refund',
                headers=headers
            )

            if response.status_code == 201:
                refund_data = response.json()
                # 更新订单状态
                order.status = 'REFUNDED'
                order.refund_id = refund_data['id']
                order.save()
                
                return DetailResponse(data={
                    'order_id': order.order_id,
                    'refund_id': refund_data['id'],
                    'status': 'REFUNDED'
                })
            else:
                return ErrorResponse(msg="Refund failed")

        except Exception as e:
            return ErrorResponse(msg=f"Error processing refund: {str(e)}")

    @action(methods=['GET'], detail=True)
    def get_order_details(self, request, pk=None):
        """
        获取订单详情
        """
        try:
            order = self.get_object()
            access_token = self.get_paypal_access_token()
            
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            response = requests.get(
                f'https://api-m.sandbox.paypal.com/v2/checkout/orders/{order.order_id}',
                headers=headers
            )

            if response.status_code == 200:
                return DetailResponse(data=response.json())
            else:
                return ErrorResponse(msg="Failed to get order details")

        except Exception as e:
            return ErrorResponse(msg=f"Error getting order details: {str(e)}")

    @action(methods=['POST'], detail=False)
    def create_order_with_goods(self, request):
        """
        创建订单并关联商品
        """
        try:
            # 获取商品信息
            goods_list = request.data.get('goods', [])
            if not goods_list:
                return ErrorResponse(msg="No goods provided")

            # 计算订单总金额
            total_amount = 0
            for item in goods_list:
                goods = Goods.objects.get(id=item['goods_id'])
                quantity = item.get('quantity', 1)
                price = float(goods.goods_price)
                total_amount += price * quantity

            # 创建PayPal订单
            access_token = self.get_paypal_access_token()
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            # 创建订单记录
            order = Orders.objects.create(
                user=request.user,
                amount=total_amount,
                currency='USD',
                status='CREATED',
                description=request.data.get('description', '')
            )

            # 创建订单商品关联
            for item in goods_list:
                goods = Goods.objects.get(id=item['goods_id'])
                OrderGoods.objects.create(
                    order=order,
                    goods=goods,
                    quantity=item.get('quantity', 1),
                    price=float(goods.goods_price)
                )

            # 创建PayPal支付订单
            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            payload = {
                "intent": "CAPTURE",
                "purchase_units": [{
                    "reference_id": str(order.id),
                    "amount": {
                        "currency_code": "USD",
                        "value": str(total_amount)
                    },
                    "description": order.description
                }],
                "application_context": {
                    "return_url": f"{settings.FRONTEND_URL}/payment/success",
                    "cancel_url": f"{settings.FRONTEND_URL}/payment/cancel"
                }
            }

            response = requests.post(
                'https://api-m.sandbox.paypal.com/v2/checkout/orders',
                headers=headers,
                json=payload
            )
            
            if response.status_code == 201:
                paypal_order = response.json()
                # 更新订单的PayPal信息
                order.paypal_order_id = paypal_order['id']
                order.save()
                
                return DetailResponse(data={
                    'order_id': order.id,
                    'paypal_order_id': paypal_order['id'],
                    'links': paypal_order['links']
                })
            else:
                # 如果PayPal创建失败,删除本地订单
                order.delete()
                return ErrorResponse(msg="Failed to create PayPal order")

        except Exception as e:
            return ErrorResponse(msg=f"Error creating order: {str(e)}")

    @action(methods=['GET'], detail=True)
    def get_order_goods(self, request, pk=None):
        """
        获取订单关联的商品信息
        """
        try:
            order = self.get_object()
            order_goods = OrderGoods.objects.filter(order=order)
            data = [{
                'goods_id': item.goods.id,
                'goods_name': item.goods.goods_name,
                'quantity': item.quantity,
                'price': item.price,
                'total': float(item.quantity * item.price)
            } for item in order_goods]
            return SuccessResponse(data=data)
        except Exception as e:
            return ErrorResponse(msg=f"Error getting order goods: {str(e)}")

    @action(methods=['POST'], detail=True)
    def update_order_goods(self, request, pk=None):
        """
        更新订单商品信息
        """
        try:
            order = self.get_object()
            if order.status != 'CREATED':
                return ErrorResponse(msg="Can only modify orders in CREATED status")

            goods_list = request.data.get('goods', [])
            if not goods_list:
                return ErrorResponse(msg="No goods provided")

            # 删除原有的订单商品关联
            OrderGoods.objects.filter(order=order).delete()

            # 创建新的订单商品关联
            total_amount = 0
            for item in goods_list:
                goods = Goods.objects.get(id=item['goods_id'])
                quantity = item.get('quantity', 1)
                price = float(goods.goods_price)
                total_amount += price * quantity
                
                OrderGoods.objects.create(
                    order=order,
                    goods=goods,
                    quantity=quantity,
                    price=price
                )

            # 更新订单金额
            order.amount = total_amount
            order.save()

            return SuccessResponse(msg="Order goods updated successfully")
        except Exception as e:
            return ErrorResponse(msg=f"Error updating order goods: {str(e)}")

    @action(methods=['GET'], detail=True)
    def payment_status(self, request, pk=None):
        """
        查询支付状态
        """
        try:
            order = self.get_object()
            access_token = self.get_paypal_access_token()
            
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            response = requests.get(
                f'https://api-m.sandbox.paypal.com/v2/checkout/orders/{order.paypal_order_id}',
                headers=headers
            )

            if response.status_code == 200:
                payment_data = response.json()
                return DetailResponse(data={
                    'order_id': order.order_id,
                    'status': payment_data['status'],
                    'payment_source': payment_data.get('payment_source', {}),
                    'purchase_units': payment_data.get('purchase_units', [])
                })
            else:
                return ErrorResponse(msg="Failed to get payment status")

        except Exception as e:
            return ErrorResponse(msg=f"Error getting payment status: {str(e)}")

    @action(methods=['POST'], detail=True)
    def cancel_order(self, request, pk=None):
        """
        取消订单
        """
        try:
            order = self.get_object()
            if order.status not in ['CREATED', 'APPROVED']:
                return ErrorResponse(msg="Can only cancel orders in CREATED or APPROVED status")

            # 如果已经创建了PayPal订单，需要在PayPal上也取消
            if order.paypal_order_id:
                access_token = self.get_paypal_access_token()
                if not access_token:
                    return ErrorResponse(msg="Failed to get PayPal access token")

                headers = {
                    'Content-Type': 'application/json',
                    'Authorization': f'Bearer {access_token}',
                }

                response = requests.post(
                    f'https://api-m.sandbox.paypal.com/v2/checkout/orders/{order.paypal_order_id}/cancel',
                    headers=headers
                )

                if response.status_code not in [200, 204]:
                    return ErrorResponse(msg="Failed to cancel PayPal order")

            # 更新订单状态
            order.status = 'CANCELLED'
            order.save()

            return DetailResponse(msg="Order cancelled successfully")

        except Exception as e:
            return ErrorResponse(msg=f"Error cancelling order: {str(e)}")

    @action(methods=['POST'], detail=True)
    def partial_refund(self, request, pk=None):
        """
        部分退款
        """
        try:
            order = self.get_object()
            if not order.payment_id:
                return ErrorResponse(msg="No payment ID found for this order")

            refund_amount = request.data.get('amount')
            if not refund_amount:
                return ErrorResponse(msg="Refund amount is required")

            access_token = self.get_paypal_access_token()
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            payload = {
                "amount": {
                    "value": str(refund_amount),
                    "currency_code": order.currency
                }
            }

            response = requests.post(
                f'https://api-m.sandbox.paypal.com/v2/payments/captures/{order.payment_id}/refund',
                headers=headers,
                json=payload
            )

            if response.status_code == 201:
                refund_data = response.json()
                
                # 记录退款信息
                order.refund_id = refund_data['id']
                if float(refund_amount) >= float(order.amount):
                    order.status = 'REFUNDED'
                else:
                    order.status = 'PARTIALLY_REFUNDED'
                order.save()
                
                return DetailResponse(data={
                    'order_id': order.order_id,
                    'refund_id': refund_data['id'],
                    'amount': refund_amount,
                    'status': order.status
                })
            else:
                return ErrorResponse(msg="Refund failed")

        except Exception as e:
            return ErrorResponse(msg=f"Error processing refund: {str(e)}")

    @action(methods=['GET'], detail=True)
    def payment_history(self, request, pk=None):
        """
        获取支付历史
        """
        try:
            order = self.get_object()
            access_token = self.get_paypal_access_token()
            
            if not access_token:
                return ErrorResponse(msg="Failed to get PayPal access token")

            headers = {
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {access_token}',
            }

            # 获取支付历史
            response = requests.get(
                f'https://api-m.sandbox.paypal.com/v2/payments/captures/{order.payment_id}',
                headers=headers
            )

            if response.status_code == 200:
                payment_data = response.json()
                
                # 如果有退款，获取退款信息
                refunds = []
                if order.refund_id:
                    refund_response = requests.get(
                        f'https://api-m.sandbox.paypal.com/v2/payments/refunds/{order.refund_id}',
                        headers=headers
                    )
                    if refund_response.status_code == 200:
                        refunds.append(refund_response.json())

                return DetailResponse(data={
                    'order_id': order.order_id,
                    'payment': payment_data,
                    'refunds': refunds
                })
            else:
                return ErrorResponse(msg="Failed to get payment history")

        except Exception as e:
            return ErrorResponse(msg=f"Error getting payment history: {str(e)}")